package com.huangjue.backend.utils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * 后端加密工具类
 * 实现RSA+AES混合加密方案
 * 
 * 加密流程：
 * 1. 生成随机AES密钥
 * 2. 使用AES加密数据
 * 3. 使用RSA公钥加密AES密钥
 * 4. 将加密后的AES密钥和加密数据一起发送
 * 
 * 解密流程：
 * 1. 使用RSA私钥解密AES密钥
 * 2. 使用解密后的AES密钥解密数据
 */
public class EncryptionUtil {
    
    // RSA密钥对
    private static KeyPair rsaKeyPair;
    // RSA公钥
    private static String publicKeyString;
    // RSA私钥
    private static String privateKeyString;
    
    // AES算法 - 使用ECB模式简化处理
    private static final String AES_ALGORITHM = "AES/ECB/PKCS5Padding";
    // RSA算法
    private static final String RSA_ALGORITHM = "RSA";
    // RSA密钥长度
    private static final int RSA_KEY_SIZE = 1024;
    // AES密钥长度
    private static final int AES_KEY_SIZE = 256;
    
    static {
        // 初始化时生成RSA密钥对
        generateRSAKeyPair();
    }
    
    /**
     * 生成RSA密钥对
     */
    private static void generateRSAKeyPair() {
        try {
            // 使用固定的密钥对进行测试（与前端保持一致）
            // 这些是从Node.js生成的测试密钥对
            publicKeyString = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBMfcQRjk+uAsPIAPadpoPx+vt" +
                             "xQA1A5YmvAzdtLpGeRT0mtfpLmWnTLbFkoi0IEXnZ6x8EBHCi5fsoBnTk/25rdmH" +
                             "EFpfABvsWVODJciaSReoKJXjyhrLLMzWpbJfi6SkEZ7EXwbg4iePQZdQfGS8jJlt" +
                             "6D7m+UStvdfZV2FbuwIDAQAB";
            
            privateKeyString = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMEx9xBGOT64Cw8g" +
                              "A9p2mg/H6+3FADUDlia8DN20ukZ5FPSa1+kuZadMtsWSiLQgRednrHwQEcKLl+yg" +
                              "GdOT/bmt2YcQWl8AG+xZU4MlyJpJF6golePKGssszNalsl+LpKQRnsRfBuDiJ49B" +
                              "l1B8ZLyMmW3oPub5RK2919lXYVu7AgMBAAECgYA5oAmtlQSmLIc/77C2jQHPCzbY" +
                              "KRayuWskCptb1fhp5NvXSgh0yR4RFNS/gcG82JOBPm84YiKqALFEJ00Myuu23XfC" +
                              "6PHkVx61+6C/CP/6kZWAtXTWj6tk6Yxbmg1UPh46/nMqkAeYZ2WwTxm5ZumWNc1o" +
                              "qPZ9Rkuh7ClUoWXHgQJBAPJQhfySZloOcmsdYubLfPzZgmnfYw6ZzZQPIGwjRmK4" +
                              "DSf+H0Vuh2yRAXBSf7JYL+jr43ACxi47XOpkOStAdUsCQQDMG0FKaDJcx6/AIVjZ" +
                              "o4stwSEmGTGgSoD2i0BG9QHbNN1cKar6PcWlLXnL5ia+K87O5krzCKhnmZP8HIA8" +
                              "IF1RAkAjAbcZshzPTd8B0pEDPsqjzNimavtolJe6mCTa+o2knWppKLFj2n/+E0Td" +
                              "8U05erwRLmMBP6VZ8IGP60LHGNzZAkEAp5/upCwkyFva9ACvFragtCf7kG16ezkU" +
                              "5uYAGQZYyu2Eqo8x8yhOLNTHRXSz9tTFmNg7T5OZstPHXHMPwdGWsQJBALgmicHk" +
                              "J8Mns41pbE/oCISgtJQXUMKaqQWzC5aeOA9ZuRSnJHo/Poc8bT1WdPQceeyl8uzG" +
                              "vJVFoSXJU7zi8po=";
            
            System.out.println("RSA密钥对设置成功（测试密钥）");
        } catch (Exception e) {
            System.err.println("设置RSA密钥对失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取RSA公钥
     * @return RSA公钥字符串（PEM格式）
     */
    public static String getPublicKey() {
        // 将Base64编码的公钥转换为PEM格式
        return "-----BEGIN PUBLIC KEY-----\n" + 
               publicKeyString + 
               "\n-----END PUBLIC KEY-----";
    }
    
    /**
     * 生成随机AES密钥
     * @return AES密钥的Base64字符串
     * @throws Exception 生成失败时抛出异常
     */
    public static String generateAESKey() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(AES_KEY_SIZE);
        SecretKey secretKey = keyGenerator.generateKey();
        return Base64.getEncoder().encodeToString(secretKey.getEncoded());
    }
    
    /**
     * 使用AES加密数据
     * @param data 要加密的数据
     * @param key AES密钥的Base64字符串
     * @return 加密后的Base64字符串
     * @throws Exception 加密失败时抛出异常
     */
    public static String encryptWithAES(String data, String key) throws Exception {
        try {
            System.out.println("开始AES加密...");
            System.out.println("数据: " + data);
            System.out.println("密钥长度: " + (key != null ? key.length() : 0));
            
            SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.getDecoder().decode(key), "AES");
            System.out.println("密钥规格创建成功");
            
            // 使用ECB模式加密（简化处理）
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
            System.out.println("加密器初始化成功");
            
            byte[] encryptedBytes = cipher.doFinal(data.getBytes("UTF-8"));
            String result = Base64.getEncoder().encodeToString(encryptedBytes);
            System.out.println("AES加密成功，结果长度: " + result.length());
            return result;
        } catch (Exception e) {
            System.err.println("AES加密失败: " + e.getMessage());
            System.err.println("异常类型: " + e.getClass().getSimpleName());
            throw e;
        }
    }
    
    /**
     * 使用AES解密数据
     * @param encryptedData 加密数据的Base64字符串
     * @param key AES密钥的Base64字符串
     * @return 解密后的字符串
     * @throws Exception 解密失败时抛出异常
     */
    public static String decryptWithAES(String encryptedData, String key) throws Exception {
        try {
            System.out.println("开始AES解密...");
            System.out.println("加密数据长度: " + (encryptedData != null ? encryptedData.length() : 0));
            System.out.println("密钥长度: " + (key != null ? key.length() : 0));
            
            // 解码Base64数据
            byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);
            System.out.println("解码后字节长度: " + encryptedBytes.length);
            
            // 直接使用ECB模式解密（简化处理）
            System.out.println("使用ECB模式解密");
            SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.getDecoder().decode(key), "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
            
            byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
            String result = new String(decryptedBytes, "UTF-8");
            System.out.println("ECB模式解密成功，结果长度: " + result.length());
            System.out.println("解密结果: " + result);
            return result;
            
        } catch (Exception e) {
            System.err.println("AES解密失败: " + e.getMessage());
            System.err.println("异常类型: " + e.getClass().getSimpleName());
            throw e;
        }
    }
    
    /**
     * 使用RSA加密数据
     * @param data 要加密的数据
     * @param publicKeyString RSA公钥字符串（PEM格式或Base64格式）
     * @return 加密后的Base64字符串
     * @throws Exception 加密失败时抛出异常
     */
    public static String encryptWithRSA(String data, String publicKeyString) throws Exception {
        byte[] publicKeyBytes;
        
        // 检查是否为PEM格式
        if (publicKeyString.contains("-----BEGIN PUBLIC KEY-----")) {
            // PEM格式，提取Base64部分
            String pemContent = publicKeyString
                .replace("-----BEGIN PUBLIC KEY-----", "")
                .replace("-----END PUBLIC KEY-----", "")
                .replaceAll("\\s", "");
            publicKeyBytes = Base64.getDecoder().decode(pemContent);
        } else {
            // Base64格式
            publicKeyBytes = Base64.getDecoder().decode(publicKeyString);
        }
        
        PublicKey publicKey = KeyFactory.getInstance(RSA_ALGORITHM)
                .generatePublic(new X509EncodedKeySpec(publicKeyBytes));
        
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        
        byte[] encryptedBytes = cipher.doFinal(data.getBytes("UTF-8"));
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }
    
    /**
     * 使用RSA解密数据
     * @param encryptedData 加密数据的Base64字符串
     * @return 解密后的字符串
     * @throws Exception 解密失败时抛出异常
     */
    public static String decryptWithRSA(String encryptedData) throws Exception {
        try {
            System.out.println("RSA解密开始...");
            System.out.println("私钥字符串长度: " + (privateKeyString != null ? privateKeyString.length() : 0));
            System.out.println("加密数据长度: " + (encryptedData != null ? encryptedData.length() : 0));
            
            byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyString);
            System.out.println("私钥字节长度: " + privateKeyBytes.length);
            
            PrivateKey privateKey = KeyFactory.getInstance(RSA_ALGORITHM)
                    .generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
            System.out.println("私钥对象创建成功");
            
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            System.out.println("RSA解密器初始化成功");
            
            byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);
            System.out.println("加密字节长度: " + encryptedBytes.length);
            
            byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
            System.out.println("RSA解密成功，解密字节长度: " + decryptedBytes.length);
            
            String result = new String(decryptedBytes, "UTF-8");
            System.out.println("RSA解密完成，结果长度: " + result.length());
            
            return result;
        } catch (Exception e) {
            System.err.println("RSA解密失败: " + e.getMessage());
            System.err.println("异常类型: " + e.getClass().getSimpleName());
            throw e;
        }
    }
    
    /**
     * 解密前端发送的加密数据
     * @param encryptedData 加密的数据
     * @param encryptedAESKey 加密的AES密钥
     * @return 解密后的数据
     * @throws Exception 解密失败时抛出异常
     */
    public static String decryptRequestData(String encryptedData, String encryptedAESKey) throws Exception {
        try {
            System.out.println("开始解密请求数据...");
            System.out.println("加密数据长度: " + (encryptedData != null ? encryptedData.length() : 0));
            System.out.println("加密AES密钥长度: " + (encryptedAESKey != null ? encryptedAESKey.length() : 0));
            
            // 1. 使用RSA私钥解密AES密钥
            System.out.println("正在解密AES密钥...");
            String aesKey = decryptWithRSA(encryptedAESKey);
            System.out.println("AES密钥解密成功，长度: " + aesKey.length());
            
            // 2. 使用解密后的AES密钥解密数据
            System.out.println("正在解密数据...");
            String decryptedData = decryptWithAES(encryptedData, aesKey);
            System.out.println("数据解密成功，长度: " + decryptedData.length());
            
            return decryptedData;
        } catch (Exception e) {
            System.err.println("解密失败: " + e.getMessage());
            System.err.println("当前私钥长度: " + (privateKeyString != null ? privateKeyString.length() : 0));
            throw e;
        }
    }
    
    /**
     * 加密响应数据
     * @param data 要加密的响应数据
     * @return 包含加密数据的Map
     * @throws Exception 加密失败时抛出异常
     */
    public static Map<String, Object> encryptResponseData(String data) throws Exception {
        try {
            System.out.println("开始加密响应数据...");
            System.out.println("响应数据: " + data);
            
            // 1. 生成新的AES密钥
            String aesKey = generateAESKey();
            System.out.println("生成的AES密钥: " + aesKey);
            
            // 2. 使用AES加密数据
            String encryptedData = encryptWithAES(data, aesKey);
            System.out.println("AES加密结果: " + encryptedData);
            
            // 3. 使用RSA公钥加密AES密钥（使用PEM格式）
            String publicKeyPEM = getPublicKey();
            String encryptedAESKey = encryptWithRSA(aesKey, publicKeyPEM);
            System.out.println("RSA加密AES密钥结果: " + encryptedAESKey);
            
            // 4. 返回加密结果
            Map<String, Object> result = new HashMap<>();
            result.put("encryptedData", encryptedData);
            result.put("encryptedAESKey", encryptedAESKey);
            result.put("timestamp", System.currentTimeMillis());
            
            System.out.println("响应数据加密完成");
            return result;
        } catch (Exception e) {
            System.err.println("响应数据加密失败: " + e.getMessage());
            throw e;
        }
    }
    
    /**
     * 使用PBKDF2派生密钥和IV
     * @param password 密码
     * @param salt 盐值
     * @param key 输出密钥
     * @param iv 输出IV
     * @throws Exception 派生失败时抛出异常
     */
    private static void deriveKeyAndIV(byte[] password, byte[] salt, byte[] key, byte[] iv) throws Exception {
        try {
            System.out.println("开始PBKDF2密钥派生...");
            System.out.println("密码长度: " + password.length);
            System.out.println("盐值长度: " + salt.length);
            
            // 使用PBKDF2派生密钥
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            PBEKeySpec spec = new PBEKeySpec(new String(password, "UTF-8").toCharArray(), salt, 1, 48); // 48字节 = 32字节密钥 + 16字节IV
            SecretKey tmp = factory.generateSecret(spec);
            byte[] derived = tmp.getEncoded();
            
            System.out.println("派生密钥长度: " + derived.length);
            
            // 分离密钥和IV
            if (derived.length >= 48) {
                System.arraycopy(derived, 0, key, 0, 32);
                System.arraycopy(derived, 32, iv, 0, 16);
                System.out.println("密钥和IV分离成功");
            } else {
                throw new Exception("派生的密钥长度不足: " + derived.length + " < 48");
            }
        } catch (Exception e) {
            System.err.println("PBKDF2密钥派生失败: " + e.getMessage());
            throw e;
        }
    }
    
    /**
     * 检查时间戳是否有效（防止重放攻击）
     * @param timestamp 时间戳
     * @param maxAge 最大有效期（毫秒）
     * @return 是否有效
     */
    public static boolean isValidTimestamp(long timestamp, long maxAge) {
        long currentTime = System.currentTimeMillis();
        return Math.abs(currentTime - timestamp) <= maxAge;
    }
} 